package com.hsu.hsurpc.protocal;

import com.hsu.hsurpc.model.RpcRequest;
import com.hsu.hsurpc.model.RpcResponse;
import com.hsu.hsurpc.serializer.Serializer;
import com.hsu.hsurpc.serializer.SerializerFactory;
import io.vertx.core.buffer.Buffer;

import java.io.IOException;

/**
 * 协议消息解码器
 * 用于将 Buffer 解码为 ProtocolMessage 对象
 * @Author Hsu琛君珩
 * @Date 2024-09-23 10:58
 * @Description
 * @Version: v1.0.0
 */
public class ProtocolMessageDecoder {

    /**
     * 解码消息，将 Buffer 转换为 ProtocolMessage 对象
     *
     * @param buffer 待解码的 Buffer
     * @return 解码后的 ProtocolMessage 对象
     * @throws IOException 当反序列化出错时抛出
     */
    public static ProtocolMessage<?> decode(Buffer buffer) throws IOException {
        // 初始化并读取消息头中的各个字段
        ProtocolMessage.Header header = new ProtocolMessage.Header();
        byte magic = buffer.getByte(0);
        // 校验魔数是否合法
        if (magic != ProtocolConstant.PROTOCOL_MAGIC) {
            throw new RuntimeException("非法的消息魔数");
        }
        header.setMagic(magic);                       // 设置魔数
        header.setVersion(buffer.getByte(1));       // 设置版本号
        header.setSerializer(buffer.getByte(2));    // 设置序列化方式
        header.setType(buffer.getByte(3));          // 设置消息类型
        header.setStatus(buffer.getByte(4));        // 设置状态码
        header.setRequestId(buffer.getLong(5));     // 设置请求 ID
        header.setBodyLength(buffer.getInt(13));   // 设置消息体长度
        // 根据消息体长度读取消息体内容
        byte[] bodyBytes = buffer.getBytes(17, 17 + header.getBodyLength());
        // 根据消息体中的序列化形式获取对应的序列化器
        ProtocolMessageSerializerEnum serializerEnum = ProtocolMessageSerializerEnum.getEnumByKey(header.getSerializer());
        if (serializerEnum == null) {
            throw new RuntimeException("不支持的序列化协议");
        }
        Serializer serializer = SerializerFactory.getInstance(serializerEnum.getValue());
        // 根据消息类型解析消息体
        ProtocolMessageTypeEnum messageTypeEnum = ProtocolMessageTypeEnum.getEnumByKey(header.getType());
        if (messageTypeEnum == null) {
            throw new RuntimeException("不支持的消息类型");
        }
        // 解析消息体内容并返回 ProtocolMessage 对象
        switch (messageTypeEnum) {
            case REQUEST:
                RpcRequest request = serializer.deserialize(bodyBytes, RpcRequest.class);
                return new ProtocolMessage<>(header, request);
            case RESPONSE:
                RpcResponse response = serializer.deserialize(bodyBytes, RpcResponse.class);
                return new ProtocolMessage<>(header, response);
            case HEART_BEAT:
            case OTHERS:
            default:
                throw new RuntimeException("暂不支持该消息类型");
        }
    }
}
